package com.clt.ess.service.impl;

import com.alibaba.fastjson.JSON;
import com.clt.ess.CABeen.*;
import com.clt.ess.base.Constant;
import com.clt.ess.base.GJZWConstant;
import com.clt.ess.gjzw.utils.GsonUtil;
import com.clt.ess.service.ICAService;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import static com.clt.ess.base.GJZWConstant.AuthIP;
import static com.clt.ess.base.GJZWConstant.CAURL;
import static com.clt.ess.gjzw.utils.CypherUtil.signValueCA;
import static com.clt.ess.utils.StringUtils.getRandom16;

@Service
public class CAServiceImpl implements ICAService {
    //CA服务地址

    /**
     * 获取证书的流程  先获取服务端随机数，随机数拼接去申请证书，
     * 申请成功后，得到任务ID，任务ID查询证书。
     *
     * @param OrganizationName 统一社会信用代码+单位名称
     * @param CommonName       省市区(6个字节)+印章赋码（8个字节）
     * @param certType         证书类型个人证书 0 单位证书 1  服务器证书 2  大于2 预留扩展
     * @param publicKey        证书公钥信息
     * @param NotBefore        证书有效期起始时间
     * @param NotAfter         证书有效期结束时间
     * @return 证书包
     */
    @Override
    public CheckResultPackage getCertFormCA(String OrganizationName, String CommonName, String certType, String publicKey
            , String NotBefore, String NotAfter) {
        //获取客户端随机数
        String RandomA = getRandom16();
        //服务端随机数
        String RandomB = applyServiceRandom(RandomA);
        if (RandomB == null) {
            return null;
        }
        //组织申请证书的参数bean
        ApplySealCertRequest applySealCertRequest = new ApplySealCertRequest();
        //设置随机数组合
        applySealCertRequest.setTokenInfo(RandomA + RandomB);
        //组织证书数据
        ApplicationData applySealCertData = new ApplicationData();
        //用于区分请求列表的单个请求  16位
        applySealCertData.setRequestID(getRandom16());
        //证书类型
        applySealCertData.setCertType(certType);
        //国家
        applySealCertData.setCountryName("CN");
        //证书主体的组织项  电子印章标识持有者对应的“统一社会信用代码+单位名称”组成。
        applySealCertData.setOrganizationName(OrganizationName);
        //证书主体的名称项  省市区(6个字节)+印章赋码（8个字节）
        applySealCertData.setCommonName(CommonName);
        //公钥信息
        applySealCertData.setSubjectPublicKeyInfo(publicKey);
        //证书有效期起始时间
        applySealCertData.setNotBefore(NotBefore);
        //证书有效期结束时间
        applySealCertData.setNotAfter(NotAfter);
        //证书数据的算法标识
        applySealCertData.setAlgorithm("1.2.156.1.10197.1.301");
        //证书申请信息列表
        List<ApplicationData> applicationDataList = new ArrayList<>();
        applicationDataList.add(applySealCertData);
        //添加
        applySealCertRequest.setData(applicationDataList);

        //申请证书 获取任务IDCheckResultPackage
        ApplySealCertResponse applyServiceRandomResponse = applySealCert(applySealCertRequest);

        return applyServiceRandomResponse.getData().get(0).getFilePackage();
    }

    /**
     * 吊销证书的流程  先获取服务端随机数，随机数拼接吊销证书，
     * 吊销成功后，返回申请的处理结果 0 是成功，其他表示错误。
     *
     * @param serialNumber
     * @return
     */
    @Override
    public String revokeFormCA(String serialNumber) {
        //获取客户端随机数
        String RandomA = getRandom16();
        //服务端随机数
        String RandomB = applyServiceRandom(RandomA);
        if (RandomB == null) {
            return null;
        }
        //组织吊销证书接口bean
        RevokeSealCertRequest revokeSealCertRequest = new RevokeSealCertRequest();
        //拼接随机数放入bean中
        revokeSealCertRequest.setTokenInfo(RandomA + RandomB);
        //组织入参data
        RevokeSealCertRequestData data = new RevokeSealCertRequestData();
        //用于区分请求列表的单个请求  16位
        data.setRequestID(getRandom16());
        //添加签名证书序列号
        data.setSerialNumber(serialNumber);
        //组织入参list
        List<RevokeSealCertRequestData> list = new ArrayList<>();
        list.add(data);
        revokeSealCertRequest.setData(list);
        //执行吊销证书请求
        RevokeSealCertResponse revokeSealCertResponse = revokeSealCert(revokeSealCertRequest);
        //返回吊销接口的请求结果
        if (revokeSealCertResponse == null || revokeSealCertResponse.getData() == null || revokeSealCertResponse.getData().size() <= 0) {
            return null;
        }
        return revokeSealCertResponse.getData().get(0).getErrorCode();
    }

    /**
     * 证书内容变更的流程  先获取服务端随机数，随机数拼接执行证书内容变更，
     * 变更成功后，获取到变更后的文件信息
     *
     * @param serialNumber
     * @param certType
     * @param organizationName
     * @param commonName
     * @param subjectPublicKeyInfo
     * @return
     */
    @Override
    public CheckResultPackage changeCertFormCA(String serialNumber, String certType, String organizationName, String commonName, String subjectPublicKeyInfo) {
        //获取客户端随机数
        String RandomA = getRandom16();
        //服务端随机数
        String RandomB = applyServiceRandom(RandomA);
        if (RandomB == null) {
            return null;
        }
        //组织变更证书的参数bean
        ChangeSealCertRequest changeSealCertRequest = new ChangeSealCertRequest();
        //拼接随机数放入bean中
        changeSealCertRequest.setTokenInfo(RandomA+RandomB);
        //拼接证书内容变更请求列表
        ChangeSealCertRequestData data = new ChangeSealCertRequestData();
        //用于区分请求列表的单个请求  16位
        data.setRequestID(getRandom16());
        //需要变更的签名证书序列号
        data.setSerialNumber(serialNumber);
        //添加证书类型
        data.setCertType(certType);
        //添加证书主体的国家项
        data.setCountryName("CN");
        //添加证书主体的组织项
        data.setOrganizationName(organizationName);
        //添加证书主体的名称项
        data.setCommonName(commonName);
        //添加Base64 编码的签名公钥信息
        data.setSubjectPublicKeyInfo(subjectPublicKeyInfo);
        //添加SM2 椭圆曲线公钥密码算法
        data.setAlgorithm("1.2.156.10197.1.301");
        List<ChangeSealCertRequestData> list = new ArrayList<>();
        list.add(data);
        changeSealCertRequest.setData(list);
        //执行证书变更
        ChangeSealCertResponse changeSealCertResponse = changeSealCert(changeSealCertRequest);
        //返回请求结果
        if (changeSealCertResponse == null || changeSealCertResponse.getData() == null || changeSealCertResponse.getData().size() <= 0) {
            return null;
        }
        return changeSealCertResponse.getData().get(0).getFilePackage();
    }

    /**
     * 证书延期的流程  先获取服务端随机数，随机数拼接执行延期参数，
     * 证书延期成功后，获取到变更后的文件信息
     *
     * @param serialNumber
     * @param subjectPublicKeyInfo
     * @return
     */
    @Override
    public CheckResultPackage delayCertFormCA(String serialNumber, String subjectPublicKeyInfo) {
        //获取客户端随机数
        String RandomA = getRandom16();
        //服务端随机数
        String RandomB = applyServiceRandom(RandomA);
        if (RandomB == null) {
            return null;
        }
        //组织证书延期的参数bean
        DelaySealCertRequest delaySealCertRequest = new DelaySealCertRequest();
        //拼接随机数放入bean中
        delaySealCertRequest.setTokenInfo(RandomA+RandomB);
        DelaySealCertRequestData data = new DelaySealCertRequestData();
        //用于区分请求列表的单个请求  16位
        data.setRequestID(getRandom16());
        //签名证书序列号
        data.setSerialNumber(serialNumber);
        //Base64 编码的签名公钥信息
        data.setSubjectPublicKeyInfo(subjectPublicKeyInfo);
        List<DelaySealCertRequestData> list = new ArrayList<>();
        list.add(data);
        delaySealCertRequest.setData(list);
        //执行证书延期请求
        DelaySealCertResponse delaySealCertResponse = delaySealCert(delaySealCertRequest);
        //返回请求结果
        if (delaySealCertResponse == null || delaySealCertResponse.getData() == null || delaySealCertResponse.getData().size() <= 0) {
            return null;
        }
        return delaySealCertResponse.getData().get(0).getFilePackage();
    }

    /**
     * 向CA平台申请服务端随机数
     *
     * @param random 本机生成的随机数
     * @return 服务端随机数
     */
    @Override
    public String applyServiceRandom(String random) {
        ApplyServiceRandomRequest applyServiceRandomRequest = new ApplyServiceRandomRequest();
        applyServiceRandomRequest.setTaskCode("applyServiceRandom");
        applyServiceRandomRequest.setVersion("1.0");
        //证书base64编码数据
        applyServiceRandomRequest.setApplicantCert(Constant.applicantCert);

        applyServiceRandomRequest.setRandomA(random);

        String result = HttpPostWithJson(CAURL, applyServiceRandomRequest.toString());

        if (result == null) {
            return null;
        }
        ApplyServiceRandomResponse applyServiceRandomResponse = JSON.parseObject(result, ApplyServiceRandomResponse.class);

        if ("0".equals(applyServiceRandomResponse.getResultCode())) {
            //成功
            return applyServiceRandomResponse.getRandomB();
        } else {
            return null;
        }
    }

    /**
     * 提交信息申请证书
     *
     * @return 返回结果 任务ID
     */
    @Override
    public ApplySealCertResponse applySealCert(ApplySealCertRequest applySealCertRequest) {
        //请求数据
        applySealCertRequest.setTaskCode("applySealCert");
        applySealCertRequest.setVersion("1.0");
        applySealCertRequest.setSignInfo(signValueCA(applySealCertRequest.toString().getBytes(StandardCharsets.UTF_8)));
        String result = HttpPostWithJson(CAURL, applySealCertRequest.toString());
        if (result == null) {
            return null;
        }
        ApplySealCertResponse applySealCertResponse = GsonUtil.GsonToBean(result, ApplySealCertResponse.class);
        if ("0".equals(applySealCertResponse.getResultCode())) {
            //成功 返回任务ID
            return applySealCertResponse;
        } else {
            return null;
        }
    }

    /**
     * 提交证书吊销请求
     *
     * @return 返回结果 任务ID
     */

    public RevokeSealCertResponse revokeSealCert(RevokeSealCertRequest revokeSealCertRequest) {
        //请求数据
        revokeSealCertRequest.setTaskCode("revokeSealCert");
        revokeSealCertRequest.setVersion("1.0");
        revokeSealCertRequest.setSignInfo(signValueCA(revokeSealCertRequest.toString().getBytes(StandardCharsets.UTF_8)));
        String result = HttpPostWithJson(CAURL, revokeSealCertRequest.toString());
        if (result == null) {
            return null;
        }
        RevokeSealCertResponse response = GsonUtil.GsonToBean(result, RevokeSealCertResponse.class);
        if ("0".equals(response.getResultCode())) {
            //成功 返回任务ID
            return response;
        } else {
            return null;
        }
    }

    /**
     * 证书内容变更请求(证书有效期不变)
     *
     * @return 返回结果 任务ID
     */

    public ChangeSealCertResponse changeSealCert(ChangeSealCertRequest changeSealCertRequest) {
        //请求数据
        changeSealCertRequest.setTaskCode("changeSealCert");
        changeSealCertRequest.setVersion("1.0");
        changeSealCertRequest.setSignInfo(signValueCA(changeSealCertRequest.toString().getBytes(StandardCharsets.UTF_8)));
        String result = HttpPostWithJson(CAURL, changeSealCertRequest.toString());
        if (result == null) {
            return null;
        }
        ChangeSealCertResponse response = GsonUtil.GsonToBean(result, ChangeSealCertResponse.class);
        if ("0".equals(response.getResultCode())) {
            //成功 返回任务ID
            return response;
        } else {
            return null;
        }
    }

    /**
     * 证书延期请求
     *
     * @return 返回结果 任务ID
     */

    public DelaySealCertResponse delaySealCert(DelaySealCertRequest delaySealCertRequest) {
        //请求数据
        delaySealCertRequest.setTaskCode("delaySealCert");
        delaySealCertRequest.setVersion("1.0");
        delaySealCertRequest.setSignInfo(signValueCA(delaySealCertRequest.toString().getBytes(StandardCharsets.UTF_8)));
        String result = HttpPostWithJson(CAURL, delaySealCertRequest.toString());
        if (result == null) {
            return null;
        }
        DelaySealCertResponse response = GsonUtil.GsonToBean(result, DelaySealCertResponse.class);
        if ("0".equals(response.getResultCode())) {
            //成功 返回任务ID
            return response;
        } else {
            return null;
        }
    }
    /**
     * CA系统接口请求方法
     *
     * @param url  请求地址
     * @param json 参数
     * @return 返回结果
     */
    private String HttpPostWithJson(String url, String json) {
        String returnValue = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        System.out.println("fasong" + json);
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        try {
            //第一步：创建HttpClient对象
            httpClient = HttpClients.createDefault();

            //第二步：创建httpPost对象
            HttpPost httpPost = new HttpPost(url);

            //第三步：给httpPost设置JSON格式的参数
            StringEntity requestEntity = new StringEntity(json, "utf-8");
            requestEntity.setContentEncoding("UTF-8");
            httpPost.setHeader("Content-type", "application/json");
//            httpPost.setHeader("AuthIP", "10.1.20.34");
            httpPost.setHeader("AuthIP", AuthIP);
            httpPost.setEntity(requestEntity);

            //第四步：发送HttpPost请求，获取返回值
            returnValue = httpClient.execute(httpPost, responseHandler); //调接口获取返回值时，必须用此方法
            System.out.println("fanhui" + new String(returnValue.getBytes("UTF-8"), "GBK"));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //第五步：处理返回值
        return returnValue;
    }
}
